/*
 * datetime.h
 *
 *  Created on: 2011-3-21
 *      Author: minorityee
 */

#ifndef DATETIME_H_
#define DATETIME_H_

#include "common_type.h"
#include "common_def.h"
#include <time.h>
#ifndef WIN32
	#include <sys/time.h>
#endif
#include <string.h>

class CDateTime
{
public:
	CDateTime() :
		nUTime_(0)
	{
#ifndef WIN32
		struct timeval tv;
		gettimeofday(&tv, NULL);
		nUTime_ = (int64_t)tv.tv_sec * US_PER_SECOND + tv.tv_usec;
#else
		time_t t;
		time(&t);
		nUTime_ = (int64_t) t * US_PER_SECOND;
#endif
	}
	CDateTime(int64_t nUTime) :
		nUTime_(nUTime) // microseconds
	{

	}
	CDateTime(const char* cszDateTime);
	~CDateTime();

	static CDateTime CurrentDateTime()
	{
#ifndef WIN32
		struct timeval tv;
		gettimeofday(&tv, NULL);
		int64_t currentTime = (int64_t)tv.tv_sec * US_PER_SECOND + tv.tv_usec;
#else
		time_t now;
		time(&now);
		int64_t currentTime = (int64_t) now * US_PER_SECOND;
#endif
		return CDateTime(currentTime);
	}

	// strlen為輸入輸出參數
	// 輸入時判斷szDateTIme長度是否符合
	// 輸出時返回寫入的長度
	int32_t ToString(char szDateTime[], unsigned& strlen) const;

	int32_t Year() const
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		return datetime.tm_year + 1900;
	}
	int32_t Month() const
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		return datetime.tm_mon + 1;
	}
	int32_t Day() const
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		return datetime.tm_mday;
	}
	int32_t DayOfWeek() const
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		return datetime.tm_wday + 1;
	}
	int32_t DayOfYear() const
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		return datetime.tm_yday + 1;
	}
	int32_t Hour()
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		return datetime.tm_hour;
	}
	int32_t Minute() const
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		return datetime.tm_min;
	}
	int32_t Second() const
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		return datetime.tm_sec;
	}
	int32_t MSecond() const // millisecond
	{
		int32_t msec = nUTime_ % US_PER_SECOND  ;
		msec /= MS_PER_SECOND;
		return msec;
	}
	int32_t USecond() const // microsecond
	{
		int32_t usec = nUTime_ % US_PER_SECOND;
		return usec;
	}

	void AddYear(int years)
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		datetime.tm_year += years;
		_TMToMicrosec(datetime, nUTime_);
	}
	void AddMonth(int months)
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		datetime.tm_mon += months;
		_TMToMicrosec(datetime, nUTime_);
	}
	void AddDay(int days)
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		datetime.tm_mday += days;
		_TMToMicrosec(datetime, nUTime_);
	}
	void AddHour(int hours)
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		datetime.tm_hour += hours;
		_TMToMicrosec(datetime, nUTime_);
	}
	void AddMinute(int minutes)
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		datetime.tm_min += minutes;
		_TMToMicrosec(datetime, nUTime_);
	}
	void AddSecond(int seconds)
	{
		struct tm datetime;
		_MicrosecToTM(nUTime_, datetime);
		datetime.tm_sec += seconds;
		_TMToMicrosec(datetime, nUTime_);
	}
	void AddMSecond(int mseconds)
	{
		nUTime_ += mseconds * 1000;
	}
	void AddUSecond(int useconds)
	{
		nUTime_ += useconds;
	}

	int64_t uSeconds() const
	{
		return nUTime_;
	}

	bool operator<(const CDateTime& datetime) const
	{
		return nUTime_ < datetime.nUTime_;
	}
	bool operator<=(const CDateTime& datetime) const
	{
		return nUTime_ <= datetime.nUTime_;
	}
	bool operator>(const CDateTime& datetime) const
	{
		return nUTime_ > datetime.nUTime_;
	}
	bool operator>=(const CDateTime& datetime) const
	{
		return nUTime_ >= datetime.nUTime_;
	}
	bool operator==(const CDateTime& datetime) const
	{
		return nUTime_ == datetime.nUTime_;
	}

protected:
	static void _MicrosecToTM(int64_t nUTime, struct tm& datetime)
	{
		time_t rawTime = nUTime / US_PER_SECOND;
		struct tm* pTm = localtime(&rawTime);
		memcpy(&datetime, pTm, sizeof(datetime));
	}
	static void _TMToMicrosec(const struct tm& datetime, int64_t& nUTime)
	{
		nUTime = (int64_t) mktime(const_cast<struct tm*> (&datetime))
				* US_PER_SECOND;
	}

private:
	int64_t nUTime_; // microseconds
};

#endif /* DATETIME_H_ */
